package edu.northwestern.cbits.purple_robot_manager.probes.builtin;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.database.Cursor;
import android.os.BatteryManager;
import android.os.Build;
import android.os.Bundle;
import android.os.PowerManager;
import android.preference.CheckBoxPreference;
import android.preference.PreferenceManager;
import android.preference.PreferenceScreen;
import edu.northwestern.cbits.purple_robot_manager.R;
import edu.northwestern.cbits.purple_robot_manager.activities.WebkitActivity;
import edu.northwestern.cbits.purple_robot_manager.activities.WebkitLandscapeActivity;
import edu.northwestern.cbits.purple_robot_manager.charts.SplineChart;
import edu.northwestern.cbits.purple_robot_manager.db.ProbeValuesProvider;
import edu.northwestern.cbits.purple_robot_manager.logging.LogManager;
import edu.northwestern.cbits.purple_robot_manager.probes.Probe;
public class BatteryProbe extends Probe
{
private static final String DB_TABLE = "battery_probe";
private static final String BATTERY_KEY = "BATTERY_LEVEL";
private static final boolean DEFAULT_ENABLED = true;
private static final String ENABLED = "config_probe_battery_enabled";
private boolean _isEnabled = false;
private BroadcastReceiver _receiver = null;
private long _lastCheck = 0;
@Override
public String getPreferenceKey() {
return "built_in_battery";
}
@Override
public Intent viewIntent(Context context)
{
Intent i = new Intent(context, WebkitLandscapeActivity.class);
return i;
}
@Override
public String probeCategory(Context context)
{
return context.getResources().getString(R.string.probe_device_info_category);
}
@Override
public String contentSubtitle(Context context)
{
Cursor c = ProbeValuesProvider.getProvider(context).retrieveValues(context, BatteryProbe.DB_TABLE,
this.databaseSchema());
int count = -1;
if (c != null)
{
count = c.getCount();
c.close();
}
return String.format(context.getString(R.string.display_item_count), count);
}
public Map<String, String> databaseSchema()
{
HashMap<String, String> schema = new HashMap<>();
schema.put(BatteryProbe.BATTERY_KEY, ProbeValuesProvider.REAL_TYPE);
return schema;
}
@Override
public String getDisplayContent(Activity activity)
{
try
{
String template = WebkitActivity.stringForAsset(activity, "webkit/chart_spline_full.html");
SplineChart c = new SplineChart();
ArrayList<Double> battery = new ArrayList<>();
ArrayList<Double> time = new ArrayList<>();
Cursor cursor = ProbeValuesProvider.getProvider(activity).retrieveValues(activity, BatteryProbe.DB_TABLE,
this.databaseSchema());
int count = -1;
if (cursor != null)
{
count = cursor.getCount();
while (cursor.moveToNext())
{
double d = cursor.getDouble(cursor.getColumnIndex(BatteryProbe.BATTERY_KEY));
double t = cursor.getDouble(cursor.getColumnIndex(ProbeValuesProvider.TIMESTAMP));
battery.add(d);
time.add(t);
}
cursor.close();
}
c.addSeries(activity.getString(R.string.battery_level_label), battery);
c.addTime(activity.getString(R.string.battery_time_label), time);
JSONObject json = c.dataJson(activity);
template = template.replace("{{{ highchart_json }}}", json.toString());
template = template.replace("{{{ highchart_count }}}", "" + count);
return template;
}
catch (IOException | JSONException e)
{
LogManager.getInstance(activity).logException(e);
}
return null;
}
@Override
public String name(Context context)
{
return "edu.northwestern.cbits.purple_robot_manager.probes.builtin.BatteryProbe";
}
@Override
public String title(Context context)
{
return context.getString(R.string.title_battery_probe);
}
@Override
public Bundle formattedBundle(Context context, Bundle bundle)
{
Bundle formatted = super.formattedBundle(context, bundle);
formatted.putString(context.getString(R.string.battery_tech_label),
bundle.getString(BatteryManager.EXTRA_TECHNOLOGY));
formatted.putInt(context.getString(R.string.battery_temp_label),
(int) bundle.getDouble(BatteryManager.EXTRA_TEMPERATURE, -1));
formatted.putInt(context.getString(R.string.battery_volt_label),
(int) bundle.getDouble(BatteryManager.EXTRA_VOLTAGE, -1));
int status = (int) bundle.getDouble(BatteryManager.EXTRA_STATUS, BatteryManager.BATTERY_STATUS_UNKNOWN);
switch (status)
{
case BatteryManager.BATTERY_STATUS_CHARGING:
formatted.putString(context.getString(R.string.battery_status_label),
context.getString(R.string.battery_status_charging));
break;
case BatteryManager.BATTERY_STATUS_DISCHARGING:
formatted.putString(context.getString(R.string.battery_status_label),
context.getString(R.string.battery_status_discharging));
break;
case BatteryManager.BATTERY_STATUS_FULL:
formatted.putString(context.getString(R.string.battery_status_label),
context.getString(R.string.battery_status_full));
break;
case BatteryManager.BATTERY_STATUS_NOT_CHARGING:
formatted.putString(context.getString(R.string.battery_status_label),
context.getString(R.string.battery_status_not_charging));
break;
default:
formatted.putString(context.getString(R.string.battery_status_label),
context.getString(R.string.battery_status_unknown));
}
int health = (int) bundle.getDouble(BatteryManager.EXTRA_HEALTH, BatteryManager.BATTERY_HEALTH_UNKNOWN);
switch (health)
{
case BatteryManager.BATTERY_HEALTH_COLD:
formatted.putString(context.getString(R.string.battery_health_label),
context.getString(R.string.battery_health_cold));
break;
case BatteryManager.BATTERY_HEALTH_DEAD:
formatted.putString(context.getString(R.string.battery_health_label),
context.getString(R.string.battery_health_dead));
break;
case BatteryManager.BATTERY_HEALTH_GOOD:
formatted.putString(context.getString(R.string.battery_health_label),
context.getString(R.string.battery_health_good));
break;
case BatteryManager.BATTERY_HEALTH_OVERHEAT:
formatted.putString(context.getString(R.string.battery_health_label),
context.getString(R.string.battery_health_overheat));
break;
case BatteryManager.BATTERY_HEALTH_OVER_VOLTAGE:
formatted.putString(context.getString(R.string.battery_health_label),
context.getString(R.string.battery_health_over_voltage));
break;
case BatteryManager.BATTERY_HEALTH_UNSPECIFIED_FAILURE:
formatted.putString(context.getString(R.string.battery_health_label),
context.getString(R.string.battery_health_failure));
break;
default:
formatted.putString(context.getString(R.string.battery_health_label),
context.getString(R.string.battery_health_unknown));
}
int source = (int) bundle.getDouble(BatteryManager.EXTRA_PLUGGED, 0);
switch (source)
{
case 0:
formatted.putString(context.getString(R.string.battery_plugged_label),
context.getString(R.string.battery_source_none));
break;
case BatteryManager.BATTERY_PLUGGED_AC:
formatted.putString(context.getString(R.string.battery_plugged_label),
context.getString(R.string.battery_source_ac));
break;
case BatteryManager.BATTERY_PLUGGED_USB:
formatted.putString(context.getString(R.string.battery_plugged_label),
context.getString(R.string.battery_source_usb));
break;
default:
formatted.putString(context.getString(R.string.battery_plugged_label),
context.getString(R.string.battery_source_other));
}
return formatted;
}
@Override
public boolean isEnabled(Context context)
{
if (this._receiver == null)
{
final BatteryProbe me = this;
this._receiver = new BroadcastReceiver()
{
@Override
public void onReceive(Context context, Intent intent)
{
if (me._isEnabled)
{
Bundle bundle = new Bundle();
bundle.putString("PROBE", me.name(context));
bundle.putLong("TIMESTAMP", System.currentTimeMillis() / 1000);
bundle.putBoolean("PRIORITY", true);
bundle.putAll(intent.getExtras());
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
{
PowerManager power = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
bundle.putBoolean("PRIORITY", power.isPowerSaveMode());
}
me.transmitData(context, bundle);
Map<String, Object> values = new HashMap<>();
values.put(BatteryProbe.BATTERY_KEY, bundle.getInt(BatteryManager.EXTRA_LEVEL));
values.put(ProbeValuesProvider.TIMESTAMP, (double) bundle.getLong("TIMESTAMP"));
ProbeValuesProvider.getProvider(context).insertValue(context, BatteryProbe.DB_TABLE,
me.databaseSchema(), values);
}
}
};
}
long now = System.currentTimeMillis();
if (now - this._lastCheck > 5 * 60 * 1000) {
this._lastCheck = now;
try {
context.unregisterReceiver(this._receiver);
}
catch (IllegalArgumentException e)
{
// Do nothing - receiver not registered...
}
IntentFilter filter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
context.registerReceiver(this._receiver, filter);
}
SharedPreferences prefs = Probe.getPreferences(context);
this._isEnabled = false;
if (super.isEnabled(context))
{
if (prefs.getBoolean(BatteryProbe.ENABLED, BatteryProbe.DEFAULT_ENABLED))
this._isEnabled = true;
}
return this._isEnabled;
}
@Override
public void enable(Context context)
{
SharedPreferences prefs = Probe.getPreferences(context);
Editor e = prefs.edit();
e.putBoolean(BatteryProbe.ENABLED, true);
e.commit();
}
@Override
public void disable(Context context) {
SharedPreferences prefs = Probe.getPreferences(context);
Editor e = prefs.edit();
e.putBoolean(BatteryProbe.ENABLED, false);
e.commit();
}
@Override
public String summarizeValue(Context context, Bundle bundle)
{
String status = this.getStatus(context, (int) bundle.getDouble(BatteryManager.EXTRA_STATUS));
int level = (int) bundle.getDouble(BatteryManager.EXTRA_LEVEL);
return String.format(context.getResources().getString(R.string.summary_battery_probe), level, status);
}
private String getStatus(Context context, int statusInt)
{
switch (statusInt)
{
case BatteryManager.BATTERY_STATUS_CHARGING:
return context.getString(R.string.label_battery_charging);
case BatteryManager.BATTERY_STATUS_DISCHARGING:
return context.getString(R.string.label_battery_discharging);
case BatteryManager.BATTERY_STATUS_FULL:
return context.getString(R.string.label_battery_full);
case BatteryManager.BATTERY_STATUS_NOT_CHARGING:
return context.getString(R.string.label_battery_not_charging);
}
return context.getString(R.string.label_unknown);
}
/*
*
* public Bundle formattedBundle(Context context, Bundle bundle) { Bundle
* formatted = super.formattedBundle(context, bundle);
*
* @SuppressWarnings("unchecked") ArrayList<Bundle> array =
* (ArrayList<Bundle>) bundle.get(HardwareInformationProbe.DEVICES); int
* count = (int) bundle.getDouble(HardwareInformationProbe.DEVICES_COUNT);
*
* Bundle devicesBundle = this.bundleForDevicesArray(context, array);
*
* formatted.putBundle(String.format(context.getString(R.string.
* display_bluetooth_devices_title), count), devicesBundle);
*
* return formatted; };
*/
@Override
public String summary(Context context)
{
return context.getString(R.string.summary_battery_probe_desc);
}
@Override
@SuppressWarnings("deprecation")
public PreferenceScreen preferenceScreen(Context context, PreferenceManager manager)
{
PreferenceScreen screen = super.preferenceScreen(context, manager);
screen.setTitle(this.title(context));
screen.setSummary(R.string.summary_battery_probe_desc);
CheckBoxPreference enabled = new CheckBoxPreference(context);
enabled.setTitle(R.string.title_enable_probe);
enabled.setKey(BatteryProbe.ENABLED);
enabled.setDefaultValue(BatteryProbe.DEFAULT_ENABLED);
screen.addPreference(enabled);
return screen;
}
public String assetPath(Context context)
{
return "battery-probe.html";
}
}